#include "YKThreadGetImg.h"
#include "DPGMTracking.h"
#include "YKThreadProcImg.h"
#include <QTimer>
#include <QTime>

using namespace std;

YKThreadGetImg::YKThreadGetImg(DPGMTracking* pParent)
{
  m_hSemaphore = NULL;
  m_bContinue = false;
  m_pParent = pParent;
}

YKThreadGetImg::~YKThreadGetImg()
{
  

}

void YKThreadGetImg::run()//called by thread.start()
{ 
  m_hSemaphore = OpenSemaphore(SEMAPHORE_ALL_ACCESS ,FALSE, "YKSemaphore");

  TCHAR szName[] = TEXT("YKSharedMemory");  
  int dataSize = 1024*1024*2;
  int headerSize = 2+4+4+4+2+2; //18 bytes
  int pix_size = (int)(dataSize/2.0);
  unsigned char* charBuf = NULL;
  unsigned char* idxBuf = NULL; //4 bytes
  HANDLE handle = NULL;
  m_bContinue = true;


  bool bNewImageArrived = false;
  if (m_hSemaphore == NULL)
  {	
	cout << "Server is not ready. Thread should be turned off" << endl;	
	return;
  }

  int CntOfReadingMMF = 0;
  while(m_bContinue)//m_bContinue: interface btw  main and this thread
  {	
	QTime t;
	t.start();	//~40 ms

	DWORD dwWaitResult  = WaitForSingleObject(m_hSemaphore, 300); //wait for the signal for 50 ms then timeout or enter
	switch (dwWaitResult) 
	{
	  // The semaphore object was signaled.
	case WAIT_OBJECT_0: //0 -->This got the semaphore token
	  //PERFORM TASK
	  //printf("Thread %d: wait succeeded\n", GetCurrentThreadId());
	  //fout << "Thread %d: wait succeeded " << GetCurrentThreadId() << endl;
	  //Do some work here	  
	  //Sleep(20);//Effect on Display Error? NO effect	

	  handle = OpenFileMapping(FILE_MAP_READ, FALSE, szName);//After ~500 tries, 
	  //handle = OpenFileMapping(FILE_MAP_READ, TRUE, szName); //no effect

	  //Sleep(50); //no effect
	  if (handle == NULL)
	  {
		cout << "Cannot open Mapped file" << endl;		
	  }
	  else
	  {	 
		 charBuf = (unsigned char*)MapViewOfFile(handle, FILE_MAP_READ, 0, 0,  headerSize + dataSize);
		 //charBuf is NULL after ~500 tries
		 CntOfReadingMMF++;
		 
		 unsigned short iCrntIdx = 0;
		 float fMVGanAngle = 0.0f;
		 float fPanelShiftX = 0.0f;
		 float fPanelShiftY = 0.0f;
		 unsigned short iKVOn = 0;
		 unsigned short iMVOn = 0;
		
		 int idxa = 0;
		 int idxb = 0;

		 if (charBuf != NULL)
		 {
		   //unsigned short* imgbuf = new unsigned short [pix_size];			   

		   //SUNDAY: Check first 2 bytes.
		   //If the same index, no works needed
			 //iCrntIdx: 1based as well. if 0 comes, no image yet
			//iCrntIdx = ((charBuf[1] << 8) | charBuf[0]); //1 based number is coming in from C#

			//float f;
			 uchar bProjIdx[] = { charBuf[0], charBuf[1]};
			memcpy(&iCrntIdx, &bProjIdx, sizeof(iCrntIdx));		
			
			//cout << "memcpy iCrntIdx " << iCrntIdx << endl;
			//uchar bGanAng[] = { charBuf[5], charBuf[4], charBuf[3], charBuf[2] };
			uchar bGanAng[] = { charBuf[2], charBuf[3], charBuf[4], charBuf[5] };
			memcpy(&fMVGanAngle, &bGanAng, sizeof(fMVGanAngle));

			uchar bPanOffsetX[] = { charBuf[6], charBuf[7], charBuf[8], charBuf[9] };
			memcpy(&fPanelShiftX, &bPanOffsetX, sizeof(fPanelShiftX));

			uchar bPanOffsetY[] = { charBuf[10], charBuf[11], charBuf[12], charBuf[13] };
			memcpy(&fPanelShiftY, &bPanOffsetY, sizeof(fPanelShiftY));

			uchar bKVON[] = { charBuf[14], charBuf[15] };
			memcpy(&iKVOn, &bKVON, sizeof(iKVOn));

			uchar bMVON[] = { charBuf[16], charBuf[17] };
			memcpy(&iMVOn, &bMVON, sizeof(iMVOn));

			//cout << "memcpy fMVGanAngle " << fMVGanAngle << endl;

			/*fMVGanAngle = ((charBuf[5] << 24) | (charBuf[4] << 16) | (charBuf[3] << 8) | charBuf[2]);
			fPanelShiftX = ((charBuf[9] << 24) | (charBuf[8] << 16) | (charBuf[7] << 8) | charBuf[6]);
			fPanelShiftY = ((charBuf[13] << 24) | (charBuf[12] << 16) | (charBuf[11] << 8) | charBuf[10]);*/		

			/*	if (iCrntIdx < 0)
				{
				cout << "Not a single image has arrived" << endl;
				}*/

		   //if (iCrntIdx > 1) //must be!
			  // iCrntIdx = iCrntIdx - 1;

		   //iCrntIdx =((charBuf[0]<< 8s)|charBuf[1]);
		   //cout << "received value: " << iCrntIdx << endl;

		   //m_iLastIdx_onebased initial value = 0
		   if (m_pParent->m_iLastIdx < iCrntIdx && iCrntIdx >= 0 && iCrntIdx <  m_pParent->m_iCntMaxImg)
		   {
			 cout << "New image has arrived. Index is : " << iCrntIdx << endl;
			 bNewImageArrived = true;

			 //MUTEX ON

			 m_pParent->m_mutex.lock();

			 //charBuf == NULL: below code doesn't affect
			 for (int i = 0 ; i<pix_size ; i++)
			 {	
			   idxa = i*2+1+headerSize;
			   idxb = i*2+headerSize;
			   //0: 1,0  1: 3,2 ...	
			   //m_pParent->m_arrYKImage[iCrntIdx].m_pData[i] = ((charBuf[idxa]<< 8)|charBuf[idxb]); //little endian	
			   m_pParent->m_arrYKImage[iCrntIdx].m_pData[i] = 65535-((charBuf[idxa] << 8) | charBuf[idxb]); //little endian	
			 }
			 m_pParent->m_iLastIdx = iCrntIdx;			 

			 //Completion of receiving image! record the time stamp. HHMMSSFFF
			 QTime tNow = QTime::currentTime();
			 QString strFmTime = tNow.toString("hhmmsszzz");
			 m_pParent->m_arrYKImage[iCrntIdx].m_strTimeStamp = strFmTime;
			 //m_pParent->ResetROI(m_pParent->m_arrYKImage[iCrntIdx].m_iWidth / 2, m_pParent->m_arrYKImage[iCrntIdx].m_iHeight / 2);
			 m_pParent->ResetROIByDefault(&m_pParent->m_arrYKImage[iCrntIdx]);

			 //cout << "ThreadGetImage iCrntIdx=" << iCrntIdx << " width = " << m_pParent->m_arrYKImage[iCrntIdx].m_iWidth << endl;

			 m_pParent->ui.spinBoxImgIdx->setValue(iCrntIdx);	 

			 //m_pParent->SLT_DrawProjImage(); //This takes more than 30~40 ms??
			 //emit SGL_NewImageArrived();
			 
			 //Start new Thread with partial image data
			 //Initiate new ThreadProc. This Thread is just one time thread
			 //YKThreadProcImg ThreadProc(m_pParent,iCrntIdx, 5);
			 //ThreadProc.start(QThread::NormalPriority);
			// ThreadProc.exit();//return resources as well?			 

			 /*cout << "fMVGanAngle " << fMVGanAngle << endl;
			 cout << "fPanelShiftX " << fPanelShiftX << endl;
			 cout << "fPanelShiftY " << fPanelShiftY << endl;*/

			 //iCrntIdx = 5, numofProcImg = 5 --> IDX 1 2 3 4 5 images will be processed

			 //if (iKVOn == 0 && iMVOn == 1)//kV dummy image during MV beam on

			 YKThreadProcImg* pThreadProc = new YKThreadProcImg(m_pParent, iCrntIdx, fMVGanAngle, fPanelShiftX, fPanelShiftY, (bool)iKVOn, (bool)iMVOn, 1);// if iCurntidx = 2, it will not work

			/* if (iMVOn == 0 && iKVOn == 0)
			 {
				 cout << "ERRORRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR" << endl;
			 }*/
			 
			 m_pParent->SetThreadProcPointer(pThreadProc, iCrntIdx);
			 m_pParent->m_mutex.unlock();
			 pThreadProc->start(QThread::NormalPriority);
			 pThreadProc->exit();//return resources as well?			 

			 //What if we wait for the thread is over? //no problem

			/* while (true)
			 {
			   Sleep(100);

			   if (!pThreadProc->isRunning())
			   {
				 cout << "This thread is finally closed" << endl;
				 break;
			   }
			   else
			   {
				 cout << "waiting for the thread is closed" << endl;
			   }
			 }
			 delete pThreadProc;*/
			 //delete pThreadProc;//possible?
			 //MUTEX OFF
		   }

		 /*  else
		   {
			 if (m_pParent->m_iLastIdx != iCrntIdx)//  no stop here
			  int bbb = 5;
		   }*/
		   //CloseHandle(handle);
		 }
		 else
		 {
		   cout << "charBuf is NULL" << endl; //filtered here!!		   
		   cout << "How many tries:" << CntOfReadingMMF << endl; //523,520(w/ Gap btw OpenMap
		   UnmapViewOfFile (charBuf);
		   CloseHandle(handle);
		   break;		   
		 }
		 UnmapViewOfFile (charBuf);
		 CloseHandle(handle);
	  } //end of handel != NULL

	  if (!ReleaseSemaphore( 
		m_hSemaphore,  // handle to semaphore
		1,            // increase count by one
		NULL) )       // not interested in previous count
	  {
		printf("ReleaseSemaphore error: %d\n", GetLastError()); //Access is denied.
	  }
	  if (bNewImageArrived)
	  {
		cout << "Elapsed time = " << t.elapsed() << "ms" << endl;
		bNewImageArrived =false;
	  }	  
	  break;

	case WAIT_TIMEOUT: //no need of release //258	  
	  //Sleep(50);
	  printf("Thread %d: wait timed out\n", GetCurrentThreadId());
	  //fout << "Thread %d: wait timed out " << GetCurrentThreadId() << endl;
	  break;
	} //end of switch

	 Sleep(10); //not to make CSharp process fail to connect
	//	ReleaseSemaphore(hSemaphore, 1, &prev_counter);
  }//end of while
  cout << "Thread-while loop is over" << endl;

  exec();//event roop Thread is still alive To quit thread, call exit()
}